package com.tcoding.client.controller.main;

import com.jfoenix.controls.*;
import com.jfoenix.svg.SVGGlyph;
import com.tcoding.client.AppStart;
import com.tcoding.client.bean.ComboBoxMenuVO;
import com.tcoding.client.bean.MenuVoCell;
import com.tcoding.client.components.common.CFImage;
import com.tcoding.client.controller.BaseController;
import com.tcoding.client.controller.privilege.user.ProfileController;
import com.tcoding.client.controller.sidemenu.SideMenuController;
import com.tcoding.client.event.CustomEventListener;
import com.tcoding.client.event.CustomEventManager;
import com.tcoding.client.event.SocketDataChangeEvent;
import com.tcoding.client.extend.datafx.ExtendedAnimatedFlowContainer;
import com.tcoding.client.extend.jfoenix.JFXDecorator;
import com.tcoding.client.extend.jfoenix.SnackbarExtend;
import com.tcoding.client.store.ApplicationStore;
import com.tcoding.client.utils.AlertUtil;
import com.tcoding.client.utils.ImageUtil;
import com.tcoding.client.utils.SvgGraphicUtil;
import com.tcoding.client.websocket.WSClient;
import com.tcoding.core.vo.MenuVO;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.Flow;
import io.datafx.controller.flow.FlowException;
import io.datafx.controller.flow.FlowHandler;
import io.datafx.controller.flow.context.ActionHandler;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.FlowActionHandler;
import io.datafx.controller.flow.context.ViewFlowContext;
import javafx.animation.Transition;
import javafx.application.Platform;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.util.Duration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.controlsfx.control.SearchableComboBox;
import org.controlsfx.glyphfont.Glyph;
import org.kordamp.ikonli.javafx.FontIcon;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.*;

import static io.datafx.controller.flow.container.ContainerAnimations.SWIPE_LEFT;
import static io.datafx.controller.flow.container.ContainerAnimations.SWIPE_RIGHT;

@Slf4j
@ViewController(value = "/fxml/Main.fxml", title = "Material Design Example")
public final class MainController extends BaseController {

    @FXMLViewFlowContext
    private ViewFlowContext context;
    @ActionHandler
    private FlowActionHandler actionHandler;
    @FXML
    private StackPane root;
    @FXML
    private JFXToolbar mainToolbar;
    private SnackbarExtend snackbar;
    @FXML
    private StackPane titleBurgerContainer;
    @FXML
    private JFXHamburger titleBurger;

    @FXML
    private JFXDrawersStack drawersStack;

    @FXML
    private JFXDrawer leftDrawer;
    @FXML
    private JFXDrawer rightDrawer;
    @FXML
    private JFXTabPane tabPane;

    private JFXPopup toolbarPopup;


    @FXML
    private MenuBar mainMenus;

    @FXML
    private MenuBar rightMenuBar;

    private ResourceBundle bundle;

    private Glyph settingGlyph=null;
    private SVGGlyph themeGlyph;
    private Glyph languageGlyph;
    private Glyph envelopeGlyph;

    private JFXBadge envelopeBadge;
    /**
     * init fxml when loaded.
     */
    @PostConstruct
    public void init() throws Exception {

        bundle = getBundle();
        // init the title hamburger icon
        final JFXTooltip burgerTooltip = new JFXTooltip("展开菜单");
        leftDrawer.setDefaultDrawerSize(180);
        leftDrawer.setResizeContent(true);
        leftDrawer.setOverLayVisible(false);
        leftDrawer.setResizableOnDrag(false);

        rightDrawer.setDefaultDrawerSize(180);
        rightDrawer.setResizeContent(false);
        rightDrawer.setOverLayVisible(true);

        leftDrawer.setOnDrawerOpening(e -> {
            final Transition animation = titleBurger.getAnimation();
            burgerTooltip.setText("关闭菜单");
            animation.setRate(1);
            animation.play();
        });
        leftDrawer.setOnDrawerClosing(e -> {
            final Transition animation = titleBurger.getAnimation();
            burgerTooltip.setText("展开菜单");
            animation.setRate(-1);
            animation.play();
        });
//        drawersStack.toggle(leftDrawer);
        titleBurgerContainer.setOnMouseClicked(e -> {
            drawersStack.toggle(leftDrawer);
        });

        tabPane.setId("systemTabPane");
        tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);

        JFXTooltip.setVisibleDuration(Duration.millis(3000));
        JFXTooltip.install(titleBurgerContainer, burgerTooltip, Pos.BOTTOM_CENTER);

        // create the inner flow and content
//        context = new ViewFlowContext();
        context.register("ContentPane", tabPane);
        context.register("RightDrawer", rightDrawer);
        //初始化左侧菜单
        initSideMenu();
        //初始化右侧个人信息栏
        initProfile();
        //初始化头部菜单
        initMenuBar();
        initTopMenu();
        snackbar = new SnackbarExtend(root,"INFO");
        snackbar.setPrefWidth(300);
        //初始化事件监听
        initListener();

        mainToolbar.getRightItems().add(buildSearchableCombobox());

    }

    private void initTopMenu(){
        String language = Locale.getDefault().getLanguage();
        ListProperty<MenuVoCell> listProperty = ApplicationStore.getMenuVoCells();
        listProperty.sort(Comparator.comparing(o -> o.getMenuVO().getOrderNum()));

        List<MenuItem> allItem = new ArrayList<>();
        mainMenus.getMenus().clear();

        Menu allMenu = new Menu(StringUtils.equals(language,"zh")?"菜单":"menu");
        for (MenuVoCell menuVoCell : listProperty) {
            MenuVO menuVO = menuVoCell.getMenuVO();
            ObservableList<MenuVO> childrenMenus = menuVoCell.getChildrenMenus();
            if(childrenMenus==null||childrenMenus.isEmpty()){
                MenuItem menuItem = new MenuItem(StringUtils.equals(language,"zh")?menuVO.getTitle():menuVO.getCode());
                menuItem.setUserData(menuVO);
                allMenu.getItems().add(menuItem);
                allItem.add(menuItem);
                continue;
            }

            Menu menu = new Menu(StringUtils.equals(language,"zh")?menuVO.getTitle():menuVO.getCode());
            for (MenuVO childrenMenu : childrenMenus) {
                MenuItem menuItem = new MenuItem(StringUtils.equals(language,"zh")?childrenMenu.getTitle():childrenMenu.getCode());
                menuItem.setUserData(childrenMenu);
                menu.getItems().add(menuItem);
                allItem.add(menuItem);
            }
            allMenu.getItems().add(menu);
        }

        mainMenus.getMenus().add(allMenu);

        for (MenuItem menuItem : allItem) {

            menuItem.setOnAction(e->{
                MenuItem target = (MenuItem)e.getTarget();
                MenuVO menuVO = (MenuVO)target.getUserData();
                try {
                    SideMenuController.addTab(menuVO.getTitle(),null,menuVO.getHref(),menuVO,tabPane);
                } catch (ClassNotFoundException classNotFoundException) {
                    classNotFoundException.printStackTrace();
                }
            });
        }


    }

    /**
     * 初始化左侧菜单
     *
     * @throws FlowException
     */
    private void initSideMenu() throws FlowException {
        final Duration containerAnimationDuration = Duration.millis(320);
        Flow sideMenuFlow = new Flow(SideMenuController.class);
        final FlowHandler sideMenuFlowHandler = sideMenuFlow.createHandler(context);
        leftDrawer.setSidePane(sideMenuFlowHandler.start(new ExtendedAnimatedFlowContainer(containerAnimationDuration,
                SWIPE_LEFT)));
    }

    private void initProfile() throws FlowException {
        final Duration containerAnimationDuration = Duration.millis(320);
        Flow profileFlow = new Flow(ProfileController.class);
        final FlowHandler profileFlowHandler = profileFlow.createHandler(context);
        rightDrawer.setSidePane(profileFlowHandler.start(new ExtendedAnimatedFlowContainer(containerAnimationDuration,
                SWIPE_RIGHT)));
    }

    /**
     * 初始化上方菜单
     */
    private void initMenuBar() {

        rightMenuBar.getMenus().clear();
        String avatar = ApplicationStore.getAvatar();
        JFXDecorator decorator = ApplicationStore.getDecorator();
        decorator.clearButton();
        if (StringUtils.isNotBlank(avatar)) {
            Image image;
            File f = null;
            try {
                f = File.createTempFile(UUID.randomUUID().toString(), ".png");
            } catch (IOException e) {
                e.printStackTrace();
            }
            ImageUtil.GenerateImage(avatar, f);
            if (f == null) {
                image = new Image(this.getClass().getResourceAsStream("/images/default-avatar.png"));
            } else {
                image = new Image(f.toURI().toString());
            }
            CFImage cfImage3 = new CFImage(image);
            cfImage3.setImageStyle(22,11);
            JFXRippler userAvatar = new JFXRippler();
            userAvatar.getStyleClass().add("icons-main-menu");
            userAvatar.setPosition(JFXRippler.RipplerPos.BACK);
            userAvatar.getChildren().add(cfImage3);
            userAvatar.setOnMouseClicked(e-> drawersStack.toggle(rightDrawer));
            Label name = new Label(ApplicationStore.getName());
            name.setCursor(Cursor.HAND);
            name.setTextFill(StringUtils.equals(ApplicationStore.getTheme(),"light")?Color.BLACK:Color.WHITE);
            JFXListView<Label> list = new JFXListView<>();
            list.getItems().add(buildLogoutBtn());
            JFXPopup popup = new JFXPopup(list);
            name.setOnMouseClicked(e -> popup.show(name, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT,0,20));
            HBox box = new HBox(userAvatar,name);
            box.setAlignment(Pos.CENTER_LEFT);
            box.setSpacing(14);
            settingGlyph = Glyph.create( "FontAwesome|COG").size(14).color(StringUtils.equals(ApplicationStore.getTheme(),"light")?Color.BLACK:Color.WHITE);
            JFXRippler setting = new JFXRippler(settingGlyph);
            setting.getStyleClass().add("icons-main-menu");
            setting.setPosition(JFXRippler.RipplerPos.BACK);
            box.getChildren().add(setting);

            themeGlyph = SvgGraphicUtil.buildSvgGraphic("paint-brush", 14,StringUtils.equals(ApplicationStore.getTheme(),"light")?Color.WHITE:Color.KHAKI);
            JFXRippler theme = new JFXRippler(themeGlyph);

            theme.getStyleClass().add("icons-main-menu");
            theme.setPosition(JFXRippler.RipplerPos.BACK);
            box.getChildren().add(theme);
            theme.setOnMouseClicked(event -> toggleTheme());

            languageGlyph = Glyph.create( "FontAwesome|LANGUAGE").size(14).color(StringUtils.endsWithIgnoreCase(Locale.getDefault().getLanguage(), "zh")?  Color.KHAKI:Color.WHITE);
            JFXRippler language = new JFXRippler(languageGlyph);
            language.getStyleClass().add("icons-main-menu");
            language.setPosition(JFXRippler.RipplerPos.BACK);
            box.getChildren().add(language);
            language.setOnMouseClicked(e-> toggleLanguage());


            envelopeGlyph = Glyph.create( "FontAwesome|ENVELOPE").size(14).color(StringUtils.equals(ApplicationStore.getTheme(),"light")?Color.BLACK:Color.WHITE);
            JFXRippler envelope = new JFXRippler(envelopeGlyph);
            envelope.getStyleClass().add("icons-main-menu");
            envelope.setPosition(JFXRippler.RipplerPos.BACK);
            envelopeBadge=new JFXBadge(envelope);
            envelopeBadge.setPosition(Pos.TOP_RIGHT);
            envelopeBadge.setDisable(true);
            envelopeBadge.getStyleClass().add("icons-badge");
            envelopeBadge.setText(String.valueOf(ApplicationStore.getMessageList().size()));
            JFXPopup messagePopup = new JFXPopup(buildMessageBox());
            envelope.setOnMouseClicked(e -> messagePopup.show(envelope, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT,0,20));

            box.getChildren().add(envelopeBadge);


            decorator.addButton(box);
        }

    }

    private Label buildLogoutBtn(){
        Label label = new Label("退出登录");
        label.setCursor(Cursor.HAND);
        label.setGraphic(SvgGraphicUtil.buildSvgGraphic("power-off", 14, Color.BLACK));
        label.setOnMouseClicked(ev->{
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setTitle("确认");
            alert.setHeaderText("确定退出吗？");
            Button btnOk = (Button) alert.getDialogPane().lookupButton(ButtonType.OK);
            Button btnCancel = (Button) alert.getDialogPane().lookupButton(ButtonType.CANCEL);
            btnOk.setOnAction(event -> {
                try {
                    Stage mainStage =(Stage) root.getScene().getWindow();
                    mainStage.close();
                    AppStart.openLoginWindow(context,new Stage());

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ApplicationStore.setName("");
                ApplicationStore.getAllMenu().clear();
                ApplicationStore.getMenus().clear();
                ApplicationStore.getElements().clear();
                ApplicationStore.getPermissionMenus().clear();
                ApplicationStore.getRoles().clear();
                WSClient.getInstance().close();
            });
            btnCancel.setOnAction(event -> alert.close());
            alert.show();
        });
        return label;
    }

    private void toggleTheme(){

        String theme = ApplicationStore.getTheme();
        String url ;
        Color btnColor;
        if(StringUtils.isBlank(theme)||StringUtils.equals(theme,"dark")){
            url = "/css/theme/jfoenix-main-light.css";
            theme ="light";
            btnColor = Color.BLACK;
        }else {
            url = "/css/theme/jfoenix-main-dark.css";
            theme="dark";
            btnColor = Color.WHITE;
        }


        Scene scene = root.getScene();
        ObservableList<String> stylesheets = scene.getStylesheets();
        String old = "";
        for (String stylesheet : stylesheets) {
            System.out.println(stylesheet);
            if (StringUtils.indexOf(stylesheet, "jfoenix-main") >= 0) {
                old = stylesheet;
                break;
            }
        }
        stylesheets.add(AppStart.class.getResource(url).toExternalForm());
        stylesheets.remove(old);

        ApplicationStore.setTheme(theme);
        JFXDecorator decorator = ApplicationStore.getDecorator();
        decorator.setButtonFill(btnColor);
        try {
            initSideMenu();
        } catch (FlowException e) {
            e.printStackTrace();
        }
        initTopMenu();
        initMenuBar();
    }

    private void toggleLanguage(){
        String language = Locale.getDefault().getLanguage();
        if (StringUtils.equals(language, "zh")) {
            Locale.setDefault(new Locale("en", "US"));
        } else {
            Locale.setDefault(new Locale("zh", "CN"));
        }

        reloadBundle();
        bundle = getBundle();
        try {
            initSideMenu();
            initTopMenu();
        } catch (FlowException e) {
            e.printStackTrace();
        }
        initMenuBar();
    }

    private Node buildSearchableCombobox(){

        ObservableList<ComboBoxMenuVO> objects = FXCollections.observableArrayList();
        ListProperty<MenuVoCell> listProperty = ApplicationStore.getMenuVoCells();
        for (MenuVoCell menuVoCell : listProperty) {
            ObservableList<MenuVO> childrenMenus = menuVoCell.getChildrenMenus();
            if(childrenMenus==null||childrenMenus.isEmpty()){
                MenuVO menuVO = menuVoCell.getMenuVO();
                ComboBoxMenuVO comboBoxVO = new ComboBoxMenuVO(menuVO.getCode(),menuVO.getTitle(),menuVO.getHref(),menuVO);
                objects.add(comboBoxVO);
                continue;
            }
            for (MenuVO childrenMenu : childrenMenus) {
                ComboBoxMenuVO comboBoxVO = new ComboBoxMenuVO(childrenMenu.getCode(),childrenMenu.getTitle(),childrenMenu.getHref(),childrenMenu);
                objects.add(comboBoxVO);
            }
        }

        HBox v=new HBox();
        ComboBox<ComboBoxMenuVO> searchableStringBox = new SearchableComboBox<>();
        searchableStringBox.setItems(objects);
        searchableStringBox.setMaxWidth(Double.MAX_VALUE);
        searchableStringBox.setPrefHeight(20);
        searchableStringBox.getStyleClass().addAll("main-search");

        searchableStringBox.getSelectionModel().selectedItemProperty().addListener((ob,o,n)->{
            if(n==null){
                return;
            }
            try {
                SideMenuController.addTab(n.getTitle(),null,n.getUrl(),n.getData(),tabPane);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        });

        SVGGlyph svgGlyph = SvgGraphicUtil.buildSvgGraphic("search", 12, Color.SLATEGRAY);
        v.getChildren().add(searchableStringBox);
        v.getChildren().add(svgGlyph);
        return v;
    }

    private StackPane buildMessageBox(){

        StackPane pane = new StackPane();
        pane.setPrefWidth(200);
        pane.setPrefHeight(300);
        ListProperty<String> messageList = ApplicationStore.getMessageList();
        JFXListView<Label> list = new JFXListView<>();
        list.getStyleClass().add("mylistview");
        messageList.addListener((observable, oldValue, newValue) -> {
            Platform.runLater(() -> list.getItems().add(new Label(newValue.get(newValue.size()-1))));
        });

        pane.getChildren().add(list);

        return pane;

    }

    /**
     * 处理自定义事件监听
     */
    private void initListener() {
        CustomEventManager.addListener(new CustomEventListener<SocketDataChangeEvent>() {

            /**
             * 处理器
             *
             * @param socketDataChangeEvent
             */
            @Override
            public void handler(SocketDataChangeEvent socketDataChangeEvent) {
                String text = ApplicationStore.getBellNumber();
                if(StringUtils.isBlank(text)){
                    text="0";
                }
                int integer = Integer.parseInt(text);
                integer = integer>=99?99:(integer+1);
                int finalInteger = integer;
                Platform.runLater(() ->{
                    ApplicationStore.setBellNumber(String.valueOf(finalInteger));
                    envelopeBadge.setDisable(false);
                    envelopeBadge.setText(String.valueOf(finalInteger));
                });
                JFXSnackbarLayout jfxSnackbarLayout = new JFXSnackbarLayout(socketDataChangeEvent.getTitle());
                ApplicationStore.addMessage(socketDataChangeEvent.getTitle());
                snackbar.fireEvent(new JFXSnackbar.SnackbarEvent(jfxSnackbarLayout));
            }
        });

    }

}
